using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Collections;
using System.IO;

using GURUCORE.Framework.Core.Factory;

namespace GURUCORE.Framework.Business
{
	[FactoryClass("Services","Service")]
	public class ServiceFactory : FactoryBase
	{
		public const string GLOBAL_CACHE_KEY = "ServiceFactory";



		private Hashtable m_htAssemblies;

        public ServiceFactory(string p_sFileName)
            : base(p_sFileName, typeof(ServiceInfo))
        {
            LoadAssemblies();
        }



        private void LoadAssemblies()
        {
            int nURIOffset = "file:///".Length;
            
            string sCLRFolder = string.Empty;
            try
            {
                sCLRFolder = RuntimeEnvironment.GetRuntimeDirectory();  // {1} // not safe when server config that we can't access system local file
            }
            catch
            {
                sCLRFolder = System.IO.Path.GetDirectoryName(Assembly.GetAssembly(typeof(System.Environment)).Location); // {2} == {1}, but don't affect by AssemblySecurityConfiguration (of .NET security)
            }

            FileInfo oCurrentAssemblyFile = new FileInfo(Assembly.GetExecutingAssembly().CodeBase.Substring(nURIOffset));
            string sCurrentFolder = oCurrentAssemblyFile.DirectoryName + System.IO.Path.DirectorySeparatorChar;
            string sDefaultAsblName = Assembly.GetCallingAssembly().GetName().Name + ".dll";

            m_htAssemblies = new Hashtable();

            ArrayList arrItemName = this.GetItemNames();
            foreach (string sItemName in arrItemName)
            {
                ServiceInfo oDSInfo = (ServiceInfo)this.GetItem(sItemName);
                //if is default assembly
                if (oDSInfo.ImplementationAsm.Equals(string.Empty) || oDSInfo.ImplementationAsm.Equals(sDefaultAsblName))
                {
                    try
                    {
                        Assembly oAsbl = Assembly.GetCallingAssembly();
                        m_htAssemblies.Add(oDSInfo.Name, oAsbl);
                    }
                    catch (Exception ex)
                    {
                        // TODO: GURUCORE: what's this?
                        throw ex;
                    }
                }
                else
                {
                    //first, find the assembly
                    DirectoryInfo oDirInfo;
                    oDirInfo = new DirectoryInfo(sCurrentFolder);
                    if (oDirInfo.GetFiles(oDSInfo.ImplementationAsm).Length == 0)
                    {
                        oDirInfo = new DirectoryInfo(sCLRFolder);
                        if (oDirInfo.GetFiles(oDSInfo.ImplementationAsm).Length == 0)
                        {
                            throw new Exception();
                        }
                        else
                        {
                            oDSInfo.ImplementationAsm = sCLRFolder + oDSInfo.ImplementationAsm;
                        }
                    }
                    else
                    {
                        oDSInfo.ImplementationAsm = sCurrentFolder + oDSInfo.ImplementationAsm;
                    }

                    try
                    {
                        Assembly oAsbl = Assembly.LoadFrom(oDSInfo.ImplementationAsm);
                        m_htAssemblies.Add(oDSInfo.Name, oAsbl);
                    }
                    catch (Exception ex)
                    {
                        // TODO: GURUCORE: what's this?
                        throw ex;
                    }
                }
            }
        }

		public object GetImplementation(string p_sName)
		{
			ServiceInfo oSvcInfo = (ServiceInfo)this.GetItem(p_sName);
			Assembly oAsm = (Assembly)m_htAssemblies[p_sName];

			if (oAsm != null)
			{
				string sImplementation = oSvcInfo.Implementation;
				string sLocation = oSvcInfo.Location;

				Type tImplementation = oAsm.GetType(sImplementation);
				if ((sLocation != null) && (sLocation != string.Empty))
				{
					object[] arrArgs = new object[] { sLocation };
					object oInstance = Activator.CreateInstance(tImplementation, arrArgs);
					return oInstance;
				}
				else
				{
					//object oInstance = Activator.CreateInstance(tImplementation, null);
					object oInstance = ServiceClassLoader.CreateInstance(tImplementation);
					return oInstance;
				}
			}
			else
			{
				return null;
			}
		}
	}
}
